{$F+,S-,R-,B-,O+} UNIT DRIVExx; {******************************************************************************} INTERFACE {******************************************************************************} USES DOS; type SectorArray = array[0..1023] of byte; {because DOS allows sectors AS BIG AS 1024 bytes and we don't want to over-write memory when reading a sector from a disk} fakeDPB = {3.10 revised} record bytespersex : word; {BPB & DPB} {start of standard BPB in boot record} sexperclust : byte; {BPB & DPB} FATstart : word; {BPB & DPB} numFATS : byte; {BPB & DPB} RootdirEnts : word; {BPB & DPB} SexOnSmallDisk : word; {ignore this} mediabyte : byte; {BPB & DPB} sexperFAT : word; {BPB & DPB} SexperTrack : word; {BPB ONLY} NumHeads : word; {BPB ONLY} HiddenSex : longint; {BPB ONLY} TotSexonDisk : longint; {BPB ONLY} {end of standard BPB - 25 bytes} RootdirSex : word; {calculated} ROOTstart : word; {DPB} FirstDataSec : word; {DPB} TotClusts : word; {calculated} TotDataClusts : word; {DPB} Tracks : word; {calculated} Cylinders : word; {calculated} Size : longint; {calculated} accessflag : byte; {DPB} ddunitnum : byte; {DPB} DPBDataValid : boolean; {evaluated} end; var DOSVER : real; DRDOS, DevDrvrChainValid, NCacheLoaded, {3.00} NetwareLoaded, {3.00} StackerLoaded : boolean; {3.00, modified 3.12} DriveError : longint; NumLogicaldrives, InternalFloppies, PhysicalFixed, NumBlockDevs, MachineID : byte; AllLogicalDrives, BootableDrives, Floppies, Hards : string[32]; {3.00 - change length to 32 from 26} ProcessorType : integer; BiosDateString : string[8]; PROCEDURE UpdateDrives; { Main procedure in unit. Updates GLOBAL array DRIVES. Called in unit initialization, but should be called again each time there's a chance a user can JOIN or ASSIGN a drive, or if a phantom drive might have been accessed while shelled out from the main program that USES this unit } FUNCTION DrivExists(drv:char) : boolean; FUNCTION DriveisNormal(drv:char) : boolean; FUNCTION DriveisNONDOS(drv:char) : boolean; FUNCTION DriveisHard(drv:char) : boolean; FUNCTION DriveisRAMDisk(drv:char) : boolean; FUNCTION DriveisOtherfixed(drv:char) : boolean; FUNCTION DriveisNetwork(drv:char) : boolean; FUNCTION GetNetwareDriveType(drv:char) : byte; {!3.21} FUNCTION DriveisSubsted(drv:char) : boolean; FUNCTION DriveisJoined(drv:char) : boolean; FUNCTION DriveisAssigned(drv:char) : boolean; FUNCTION DriveisIFS(drv:char) : boolean; FUNCTION DriveisAliased(drv:char) : boolean; {true only for Assigned, Joined or Substed drives} FUNCTION DriveisRemovable(drv:char) : boolean; FUNCTION RemovableDrivetype(drv:char) : byte; { returns: 0 : can't be determined, may not be removable 1 : 5.25" 360K 2 : 5.25" 1.2M 3 : 3.5" 720K 4 : 3.5" 1.44M 5 : 3.5" 2.88M 6 : TAPE 7 : Bernoulli 8 : CDROM $FF : invalid drive specified } FUNCTION DriveisPhantom(drv:char) : boolean; FUNCTION DriveMappedTo(drv:char) : char; FUNCTION ChangeLineSupported(drv:char) : boolean; FUNCTION DiskWasChanged(drv:char) : boolean; {hits the disk only if there's support for Changeline detection} FUNCTION DiskSyze(drv:char) : longint; {3.10 name change} { returns: 0 : removable drive hasn't been accessed, so no valid DPB data to use, or size is unreliable else : disk size IN BYTES; if removable, size of last disk accessed in drive} FUNCTION PhysicalType(drv:char) : byte; { This function returns what DOS thinks is the physical type: 0 : 320K/360K 1 : 1.2 M 2 : 720K 3 : 8-inch, single-density 4 : 8-inch, double-density 5 : hard disk 6 : Tape 7 : 1.44 M (only for DOS 3.3+) 8 : Optical drive? CDROM? 9 : 2.88 M (only for DOS 5.0+) 10 : other? $FF : abnormal or invalid drive specified } FUNCTION CurrentDir(drv:char) : pathstr; { returns the currently logged directory for the specified drive as a complete path, including driveletter, colon and final backslash, all in uppercase letters. If the drive doesn't exist - or it's a NetWare drive - a null string is returned } FUNCTION DefaultDrive : char; { identifies the current default drive as an uppercase letter } FUNCTION WriteDiskSectors(drv:char; first:longint; num:word; var Buf) : word; {3.10} { returns 0 if successful, otherwise BIOS error code in high byte and DOS error code in low byte. Eg, returns 128:2 for floppy disk not ready, or 2:12 for unformatted disk in drive } FUNCTION ReadDiskSectors(drv:char; first:longint; num:word; var Buf) : word; {3.10} { returns 0 if successful, otherwise BIOS error code in high byte and DOS error code in low byte. Eg, returns 128:2 for floppy disk not ready, or 2:12 for unformatted disk in drive } FUNCTION DriveIsReady(drv : char) : boolean; FUNCTION ShowBIOSDriveNum(drv:char) : byte; {3.10} { Does not try to figure out DOS redirection commands like JOIN or ASSIGN. Whatever PHYSICAL disk you would hit with a function like ReadDiskSectors(drv, 0, 1, buf) is what this returns. If DRV is not a physical disk (eg, RAMDISK) or if DRV is a phantom, the function returns 255. Based on interception of DOS INT 25h call and determination of drivenumber passed to BIOS INT 13h Fnc 02h. IMPORTANT: DOS INT 25h ignores JOIN, but DOES NOT ignore ASSIGN or SUBST! EXAMPLES: SUBST A: C:\ Y := ShowBIOSDriveNum('A'); Y returns 128, not 0 ASSIGN A: C: Y := ShowBIOSDriveNum('A'); Y returns 128, not 0 BUT... JOIN A: C:\PUKED Y := ShowBIOSDriveNum('A'); Y returns 0! (BIOS drive number for A:) Furthermore, after this JOIN command it is impossible to access drive A: with simple DOS commands, such as DIR and CHKDSK; they all return "Invalid drive specification". Yet INT 25h will still read from a floppy in the drive! Worse yet, traversing drive C: with a search program based on DOS FindFirst and FindNext, for example, will cause drive A: to be accessed when the search tries to read anything in directory C:\PUKED! } FUNCTION GETBOOT(drv:char; var S:SectorArray) : word; {3.10} { reads boot sector and puts it directly into byte array S THE ONLY CHECKING DONE BY THIS PROCEDURE IS ON PHANTOM DRIVES. ALL OTHERS WILL BE HIT BY INT 25h AND ANY REDIRECTION BY SUBST OR ASSIGN WILL AFFECT THE OUTCOME! returns 0 : no error, S contains boot sector as read $F4F4 : can't allocate buffer to receive boot sector $F5F5 : DPB for drive says bytes per sector > 1024 $F6F6 : drive is phantom $F7F7 : drive doesn't exist else : error code generated by INT 25 (Absolute Read): failed attempt to read boot sector - DOS errorcode in the low byte and BIOS error code in the high byte (eg, BIOS error 128 means no disk in drive). } FUNCTION GETDPB(drv:char; var F:fakeDPB; HitTheDisk:boolean) : word; { Puts useful drive data from DPB into F. If HITTHEDISK is FALSE, the function will just use the DPB data in memory, usually for the last disk that was accessed in the drive. Please note that some information in the FakeDPB structure F, such as sectors-per-track, is located in the disk's boot record and not in the DPB in memory. Therefore, these fields will be filled in ONLY if this function is called with HitTheDisk = TRUE since the boot sector must be read from the disk. Only drives that are *NORMAL* are allowed to be hit; aliased drives, phantom drives, non-DOS drives, etc, will not be hit. GETDPB(drv,F,FALSE) returns 0 : no error, F contains only DPB data $F7F7 : drive doesn't exist (no other return values possible) GETDPB(drv,F,TRUE) returns 0 : no error, F contains DPB data, BPB data and derived data $F4F4 : can't allocate buffer to receive boot sector $F5F5 : DPB says bytes per sector > 1024 $F6F6 : drive is not normal (could be phantom or aliased) $F7F7 : drive doesn't exist $FF00 : DOS Fnc $32 (GetDPB) failed else : error code generated by INT 25 (Absolute Read): Hi byte = BIOS error code Lo byte = DOS error code (eg, BIOS error 128 means drive not ready or no disk in drive, BIOS error 2,6 or 12 could mean disk isn't formatted). All fields of F will be zeroed out. } PROCEDURE MakeDriveActive(drv:char); { makes a phantom drive active so you don't see the obnoxious "Insert diskette... " message when you try to access it. THIS PROCEDURE CALLS UPDATEDRIVES WHEN IT'S FINISHED!! } const BPBSize = 25;